/*
 * Copyright 2017 Zhihu Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.zhihu.matisse.library.component;

import com.zhihu.matisse.library.ResourceTable;
import com.zhihu.matisse.library.utils.AttrUtils;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.render.*;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.app.Context;
import ohos.media.image.PixelMap;

public class CheckView extends Component {

    public static final int UNCHECKED = Integer.MIN_VALUE;
    private static final float STROKE_WIDTH = 3.0f; // dp
    private static final float SHADOW_WIDTH = 6.0f; // dp
    private static final int SIZE = 48; // dp
    private static final float STROKE_RADIUS = 11.5f; // dp
    private static final float BG_RADIUS = 11.0f; // dp
    private static final int CONTENT_SIZE = 16; // dp
    private boolean mCountable;
    private boolean mChecked;
    private int mCheckedNum;
    private Paint mStrokePaint;
    private Paint mBackgroundPaint;
    private Paint mTextPaint;
    private Paint mShadowPaint;
    private Element mCheckDrawable;
    private float mDensity;
    private Rect mCheckRect;
    private boolean mEnabled = true;

    public CheckView(Context context) {
        super(context);
        init(context,null);
    }

    public CheckView(Context context, AttrSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public CheckView(Context context, AttrSet attrs, String styleName) {
        super(context, attrs, styleName);
        init(context,attrs);
    }

    private void init(Context context, AttrSet attrs) {
        mDensity = AttrHelper.getDensity(context);

        mStrokePaint = new Paint();
        mStrokePaint.setAntiAlias(true);
        mStrokePaint.setStyle(Paint.Style.STROKE_STYLE);
//        mStrokePaint.setBlendMode(BlendMode.SRC_OVER);
        mStrokePaint.setStrokeWidth(10);

        int color = attrs == null ? 0xFFFFFFFF : AttrUtils.getColorFromAttr(attrs,"borderColor",0xFFFFFFFF);

        mStrokePaint.setColor(new Color(color));
        PixelMap pixelMap =  AttrUtils.getPixelMap(context,ResourceTable.Media_ic_check_white_18dp);
        mCheckDrawable = new PixelMapElement(pixelMap);
        initBackgroundPaint(attrs);
        initShadowPaint();
        addDrawTask(new CheckDraw());
    }

    public void setChecked(boolean checked) {
        if (mCountable) {
            throw new IllegalStateException("CheckView is countable, call setCheckedNum() instead.");
        }
        mChecked = checked;
        invalidate();
    }

    public void setCountable(boolean countable) {
        mCountable = countable;
    }

    public void setCheckedNum(int checkedNum) {
        if (!mCountable) {
            throw new IllegalStateException("CheckView is not countable, call setChecked() instead.");
        }
        if (checkedNum != UNCHECKED && checkedNum <= 0) {
            throw new IllegalArgumentException("checked num can't be negative.");
        }
        mCheckedNum = checkedNum;
        invalidate();
    }

    public void setEnabled(boolean enabled) {
        if (mEnabled != enabled) {
            mEnabled = enabled;
            invalidate();
        }
    }

     class CheckDraw implements DrawTask{

        @Override
        public void onDraw(Component component, Canvas canvas) {
            canvas.drawCircle((float) getWidth() / 2, (float) getHeight() / 2,
                    (float)getWidth() / 2 -20, mShadowPaint);



            // draw content
            if (mCountable) {
                if (mCheckedNum != UNCHECKED && mCheckedNum != 0) {

                    canvas.drawCircle((float) getWidth() / 2, (float) getHeight() / 2,
                            (float)getWidth() / 2 -20, mBackgroundPaint);
                    initTextPaint();
                    String text = String.valueOf(mCheckedNum);
//                    int baseX = (int) (canvas.getLocalClipBounds().getWidth() - mTextPaint.measureText(text)) / 2;
//                    int baseY = (int) (canvas.getLocalClipBounds().getHeight() - mTextPaint.descent() - mTextPaint.ascent()) / 2;
                    canvas.drawText(mTextPaint,text, (float) getWidth() / 2 - 10, (float) getHeight() / 2 + 10);
                }
            } else {
                if (mChecked) {

                    canvas.drawCircle((float) getWidth() / 2, (float) getHeight() / 2,
                            (float)getWidth() / 2 -20, mBackgroundPaint);

                    mCheckDrawable.setBounds(getCheckRect());
                    mCheckDrawable.drawToCanvas(canvas);
                }
            }
            // draw white stroke
            canvas.drawCircle((float) getWidth() / 2, (float) getHeight() / 2,
                    (float)getWidth() / 2 - 20, mStrokePaint);
            // enable hint
            setAlpha(mEnabled ? 1.0f : 0.5f);
        }
    }


    private void initShadowPaint() {
        if (mShadowPaint == null) {
            mShadowPaint = new Paint();
            mShadowPaint.setAntiAlias(true);
            mShadowPaint.setStyle(Paint.Style.FILLANDSTROKE_STYLE);
//            // all in dp
//            float outerRadius = STROKE_RADIUS + STROKE_WIDTH / 2;
//            float innerRadius = outerRadius - STROKE_WIDTH;
//            float gradientRadius = outerRadius + SHADOW_WIDTH;
//            float stop0 = (innerRadius - SHADOW_WIDTH) / gradientRadius;
//            float stop1 = innerRadius / gradientRadius;
//            float stop2 = outerRadius / gradientRadius;
//            float stop3 = 1.0f;
            mShadowPaint.setColor(new Color(0x0D000000));
        }
    }

    private void initBackgroundPaint(AttrSet attrs) {
        if (mBackgroundPaint == null) {
            mBackgroundPaint = new Paint();
            mBackgroundPaint.setAntiAlias(true);
            mBackgroundPaint.setStyle(Paint.Style.FILL_STYLE);
            int color = attrs == null ? 0xFF1E8AE8 : AttrUtils.getColorFromAttr(attrs,"backgroundColor",0xFF1E8AE8);

            mBackgroundPaint.setColor(new Color(color));
        }
    }

    private void initTextPaint() {
        if (mTextPaint == null) {
            mTextPaint = new Paint();
            mTextPaint.setAntiAlias(true);
            mTextPaint.setColor(Color.WHITE);
            mTextPaint.setFont(Font.DEFAULT_BOLD);
            mTextPaint.setTextSize(32);
        }
    }

    // rect for drawing checked number or mark
    private Rect getCheckRect() {
        if (mCheckRect == null) {
            int rectPadding = (int) (SIZE * mDensity / 2 - CONTENT_SIZE * mDensity / 2);
            mCheckRect = new Rect(rectPadding, rectPadding,
                    (int) (SIZE * mDensity - rectPadding), (int) (SIZE * mDensity - rectPadding));
        }

        return mCheckRect;
    }
}
